using System;
using System.Diagnostics;
using System.IO;

namespace HpcClusterControllerLinux
{
    public class LogWatcher
    {
        private static FileSystemWatcher watcher;
        private static long currentPosition = -1;

        private static Controller controller;

        public static void Setup(Controller f)
        {
            // set the controller to call.
            controller = f;

            // Create a new FileSystemWatcher and set its properties.
            watcher = new FileSystemWatcher();
            watcher.Path = "/var/spool/pbs/server_priv/accounting/";

            // Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories.
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;

            // Add event handlers.
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.Created += new FileSystemEventHandler(OnCreated);

            //Watching for changes only in file which name is yymmdd, y=year, m=month and d=day.
            DateTime date = DateTime.Now;
			string logname = date.Year.ToString() + date.Month.ToString("D2") + date.Day.ToString("D2");
			
			// we only set up the filter if the file already exists. Otherwise, we will wait a OnCreated event to do that.
			if (File.Exists(watcher.Path + logname)) {
				watcher.Filter = logname;
				Debug.WriteLine(String.Format("Watching file {0}{1}", watcher.Path, watcher.Filter));
				
				// we need to read the file to get the position for the next entry
				currentPosition = findEof();
			} 

            // Begin watching.
            watcher.EnableRaisingEvents = true;
        }

        public static void OnChanged(object source, FileSystemEventArgs e)
        {
            //WatchJobs returns the position of end of file, that will be where we will begin read on the next time.
			WatchJobs(e.FullPath);            
        }
		
		public static void OnCreated(object source, FileSystemEventArgs e)
        {
            DateTime date = DateTime.Now;
            watcher.Filter = date.Year.ToString() + date.Month.ToString("D2") + date.Day.ToString("D2");
			currentPosition = 0;
        }

        private static void WatchJobs(string FullPath)
        {
			// what about the thread-safety of this method?
			
			Debug.WriteLine("New log entry found.");

			try {
	            using (StreamReader sr = new StreamReader(FullPath))
	            {
	                
					// seek to the position that has been already read
					sr.BaseStream.Seek(currentPosition, SeekOrigin.Begin);
	
	                // now, walk for the next entries
					string lines;
					while ((lines = sr.ReadLine()) != null) 
					{
						if (lines.Length > 0) {
							controller.processJobEvent(lines);
						}
					}
					
					// record the reached position
	                currentPosition = sr.BaseStream.Position;
	            } 
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.Message);
				Debug.WriteLine(ex.StackTrace);	
			}
        }
		
		private static long findEof()
		{
			string path = String.Format("{0}{1}", watcher.Path, watcher.Filter);
			
			using (StreamReader sr = new StreamReader(path))
            {
                sr.BaseStream.Seek(0, SeekOrigin.End);
                return sr.BaseStream.Position;
            }
		}
    }
}
